#include "public.h"
#include "log.h"


#define	LOG_MAX_STR		1024


#define	LOG_LEVEL_ALERT		0
#define	LOG_LEVEL_ERROR		1
#define	LOG_LEVEL_WARN		2
#define	LOG_LEVEL_INFO		3
#define	LOG_LEVEL_DEBUG		4


const char *log_levels[] = {
	"alert",
	"error",
	"warn",
	"info",
	"debug"
};


struct log_s
{
	FILE			*fp;
	pthread_mutex_t		lock;
};


struct log_s	*log_open( const char *fn )
{
	struct log_s *log;

	log = (struct log_s*)malloc( sizeof(*log) );
	if( NULL == log ) 
		return NULL;
	
	log->fp = fopen( fn, "a+" );
	if( NULL == log->fp )
	{
		free( log );
		return NULL;
	}

	pthread_mutex_init( &log->lock, NULL );
	
	return log;
}


void	log_close( struct log_s *log )
{
	if( NULL == log ) 
		return;

	fclose( log->fp );
	pthread_mutex_destroy( &log->lock );
	free( log );
}



void	log_core( int level, struct log_s *log, const char *fmt, va_list ap )
{
	char	buffer[LOG_MAX_STR + 1];
	int	n;
	
	n = time_fmt( g_cur_time, buffer );
	n += sprintf( buffer + n, " [%s] ^%p^:", log_levels[level], g_cur_pid );
	n += vsnprintf( buffer + n, LOG_MAX_STR - n - 2, fmt, ap );
	strcpy( buffer + n, "\r\n" );

	fprintf( stderr, buffer );
	pthread_mutex_lock( &log->lock );
	fprintf( log->fp, buffer );
	pthread_mutex_unlock( &log->lock );
	
}



void	log_alert( struct log_s *log, const char *fmt, ... )
{
	va_list ap;

        va_start( ap , fmt );
	log_core( LOG_LEVEL_ALERT, log, fmt, ap );
	va_end( ap );	
}


void	log_error( struct log_s *log, const char *fmt, ... )
{
        va_list ap;

        va_start( ap , fmt );
        log_core( LOG_LEVEL_ERROR, log, fmt, ap );
        va_end( ap );
}


void	log_warn( struct log_s *log, const char *fmt, ... )
{
        va_list ap;

        va_start( ap , fmt );
        log_core( LOG_LEVEL_WARN, log, fmt, ap );
        va_end( ap );
}


void	log_info( struct log_s *log, const char *fmt, ... )
{
        va_list ap;

        va_start( ap , fmt );
        log_core( LOG_LEVEL_INFO, log, fmt, ap );
        va_end( ap );
}


void	_log_debug( struct log_s *log, const char *fmt, ... )
{
        va_list ap;

        va_start( ap , fmt );
        log_core( LOG_LEVEL_DEBUG, log, fmt, ap );
        va_end( ap );
}

